/***********************************************************************
 makepng.cpp - Glue between libpng's PNG writing code and an SDL drawing
 	surface.

 Created 2006.06.10 by Warren Young

 Copyright (c) 2006 by Pixel Corps.  This program may be used under
 the terms of the X11 license, a copy of which should have accompanied
 this program, in the LICENSE file.
***********************************************************************/

#include "makepng.h"

#include <png.h>
#include <SDL.h>

#include <iostream>

using namespace std;


//// SaveSurfaceAsPNG //////////////////////////////////////////////////

bool
SaveSurfaceAsPNG(SDL_Surface* pSurface, const char* pcFileName)
{
	png_structp png_ptr;
	png_infop info_ptr;
	FILE* fp;

	char* doing = "create PNG write struct";
	if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
			0, 0, 0))) {
		goto fail;
	}

	doing = "create PNG info struct";
	if (!(info_ptr = png_create_info_struct(png_ptr))) {
		goto fail;
	}

	if (setjmp(png_jmpbuf(png_ptr))) {
		goto fail;
	}

	doing = "open PNG for writing";
	if (!(fp = fopen(pcFileName, "wb"))) {
		goto fail;
	}

	doing = "init IO";
	png_init_io(png_ptr, fp);

	doing = "write header";
	png_set_IHDR(png_ptr, info_ptr, pSurface->w, pSurface->h, 8,
			PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
		    PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	doing = "allocating PNG pixel buffer";
	png_bytep row_pointers[pSurface->h];
	for (int i = 0; i < pSurface->h; ++i) {
		row_pointers[i] = (png_bytep)png_malloc(png_ptr,
				pSurface->pitch);
	}

	doing = "copying pixel data";
	for (int i = 0; i < pSurface->h; ++i) {
		memcpy(row_pointers[i],
				(char*)pSurface->pixels + (i * pSurface->pitch),
				pSurface->pitch);
	}
	png_set_rows(png_ptr, info_ptr, row_pointers);

	doing = "write PNG data";
	png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

	doing = "freeing buffers";
	for (int i = 0; i < pSurface->h; ++i) {
		png_free(png_ptr, row_pointers[i]);
	}
	png_destroy_write_struct(&png_ptr, &info_ptr);

	fclose(fp);
	return true;

fail:
	cerr << "Write_png: could not " << doing << '.' << endl;
	return false;
}
